iT邦幫忙

2024 iThome 鐵人賽

DAY 5
0
Modern Web

雙向奔赴的websocket與冰冷的react系列 第 5

[day5]觀察WebSocket運作流程

  • 分享至 

  • xImage
  •  

這篇繼續延用之前的server.js設定

今天主要就是觀察Websocket的觸發過程

前端介面

首先先建立index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    </head>
    <body>
        <h1>WebSocket Testing</h1>
        <input type="text" placeholder="發送的訊息send message" id="message" />
        <button id="connectBtn">連接WebSocket伺服器</button>
        <button id="sendBtn" disabled>發送訊息給後端</button>
        <button id="closeBtn" disabled>取消WebSocket連接</button>
        <button id="bigsend" disabled>發送大數據send 5 Mb</button>
        <div>
            <p><strong>連線狀態Connection State:</strong> <span id="state">無連線</span></p>
            <p><strong>屬性Buffered Amount:</strong> <span id="bufferedAmount">0</span></p>
            <p><strong>後端回復訊息Last Received Message:</strong> <span id="lastMessage">None</span></p>
            <p><strong>過程記錄Event Log:</strong></p>
            <ul id="eventLog"></ul>
        </div>
        <script src="/index.js"></script>
    </body>
</html>


前端架設完畢後就可以來寫後端囉

前端js互動

建立index.js
1.先捕抓dom元素還有回應渲染

let ws;
const stateLabel = document.getElementById("state");
const bufferedAmountLabel = document.getElementById("bufferedAmount");
const lastMessageLabel = document.getElementById("lastMessage");
const eventLog = document.getElementById("eventLog");
const inputMessage = document.getElementById("message");

const connectBtn = document.getElementById("connectBtn");
const sendBtn = document.getElementById("sendBtn");
const closeBtn = document.getElementById("closeBtn");
const bigsend = document.getElementById("bigsend");
//紀錄事件
function logEvent(message) {
    const li = document.createElement("li");
    li.textContent = message;
    eventLog.appendChild(li);
}

2.連接server按鈕觸發

connectBtn.addEventListener("click", () => {
    ws = new WebSocket("ws://localhost:8080");
    console.log(ws.readyState);
    setTimeout(() => {
        console.log("state:" + ws.readyState);
    }, 50);
    // 監聽 WebSocket 連接打開
    ws.onopen = () => {
        stateLabel.textContent = "Connected (State: " + ws.readyState + ")";
        sendBtn.disabled = false;
        closeBtn.disabled = false;
        bigsend.disabled = false;
        logEvent("連接開啟WebSocket connection opened");
        console.log("連接開啟");
    };

    // 監聽 WebSocket 接收到消息
    ws.onmessage = (event) => {
        lastMessageLabel.textContent = event.data;
        logEvent("後端回復Message received: " + event.data);
    };

    // 監聽 WebSocket 錯誤
    ws.onerror = (error) => {
        logEvent("WebSocket error: " + error.message);
    };

    // 監聽 WebSocket 連接關閉
    ws.onclose = () => {
        stateLabel.textContent = "Closed (State: " + ws.readyState + ")";
        sendBtn.disabled = true;
        closeBtn.disabled = true;
        bigsend.disabled = true;
        logEvent("WebSocket connection closed");
        console.log("state:" + ws.readyState);
    };

    // 監聽 bufferedAmount 變化
    const bufferedAmountInterval = setInterval(() => {
        if (ws) {
            bufferedAmountLabel.textContent = ws.bufferedAmount;
            if (ws.bufferedAmount > 0) {
                console.log(ws.bufferedAmount);
            }
        } else {
            clearInterval(bufferedAmountInterval);
        }
    }, 50);

    stateLabel.textContent = "Connecting... (State: " + ws.readyState + ")";
    logEvent("WebSocket connecting...");
});

這段主要功能為:

  • 點擊btn建立websocket連接
  • 連接成功後觸發onopen
  • 佈置其他三個event事件
  • 監控bufferedAmount

細說一下bufferedAmount,這個值代表的是前端傳輸還剩餘的量,簡單來說今天我要傳輸一個500Mb的檔案,已經傳輸了80Mb則bufferedAmount會顯示420Mb,但他只能反應前端剩餘的量,反過來後端像前端傳輸則無法偵測到後端還剩餘多少資料。

3.其餘事件觸發click

sendBtn.addEventListener("click", () => {
    if (ws && ws.readyState === WebSocket.OPEN) {
        message = inputMessage.value;
        ws.send(message);
        logEvent(`前端發送Message sent:${message}`);
    }
});

closeBtn.addEventListener("click", () => {
    if (ws) {
        ws.close();
        console.log("state:" + ws.readyState);
        stateLabel.textContent = "Closing... (State: " + ws.readyState + ")";
        logEvent("WebSocket connection closing...");
    }
});
bigsend.addEventListener("click", () => {
    let message = "message:";
    for (let i = 0; i < 500000; i++) {
        message += "x";
    }
    ws.send(message);
});

觀察

都配置好後,那我們就可以來開始觀察囉
先來複習下回應碼:

  • 0 (CONNECTING): 正在建立連接。
  • 1 (OPEN): 連接已經建立並且可以進行通信。
  • 2 (CLOSING): 連接正在關閉。
  • 3 (CLOSED): 連接已關閉或無法建立。

記得打開F12(檢視)來觀察console.log唷,先說幾個比較簡單觀察的按鈕

1.連接:當我們點擊後可看出state由0轉為1。
2.關閉:當我們點擊後使用ws.close();可看出state由1轉為2,且在2轉為3時可肉眼的觀察到有delay那就是在關閉中。
3.發送大數據:可以觀察到bufferedAmount的變化。

4.發送訊息給後端:
簡單回顧下server.js

ws.on("message", function (message) {
        console.log("接收到客戶端消息:" + message);

        ws.send("服務端回復:" + message);
    });

回到前端js,首先可以用ws.readyState來判斷是否連接,前端用ws.send()向後端發送訊息,後端接受到資料後觸發message,後端在透過ws.send()發送資料給前端ws.onmessage接受到消息列印。

這邊要注意server只能有一個message,所以如果前端有不同操作與後端溝通,就必須在server的message中做判斷唷。

所以放慢腳步一個個觀察,其實就可以很輕鬆了解Websocket運作的整個流程。

Websocket的觀察就到這囉,今天就這樣


上一篇
[day4]WebSocket持續連接
下一篇
[day6]WebSocket心跳機制
系列文
雙向奔赴的websocket與冰冷的react30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言